
#ifndef __AST_H__
#define __AST_H__

#include <string>
#include <vector>
#include <set>
#include <boost/shared_ptr.hpp>
#include <iostream>

enum AstNodeType
{
	typedef_name = 0,
	namespace_name,
	original_namespace_name,
	namespace_alias,
	class_name,
	enum_name,
	template_name,
	identifier,
	literal_,
	integer_literal,
	character_literal,
	floating_literal,
	string_literal,
	boolean_literal,
	translation_unit,
	primary_expression,
	this_expression, // ***
	bracket_expression, // ***
	id_expression,
	unqualified_id,
	unqualified_id_dctor, // ***
	qualified_id,
	nested_name_specifier,
	class_or_namespace_name,
	postfix_expression_rhs_opt,
	postfix_offset_expression_rhs, // ***
	postfix_function_expression_rhs, // ***
	postfix_dereference_expression_rhs, // ***
	postfix_pointer_expression_rhs, // ***
	postfix_dec_expression_rhs, // ***
	postfix_inc_expression_rhs, // ***
	postfix_expression,
	postfix_offset_expression, // ***
	postfix_function_expression, // ***
	postfix_dereference_expression, // ***
	postfix_pointer_expression, // ***
	postfix_dec_expression, // ***
	postfix_inc_expression, // ***
	dynamic_cast_expression, // ***
	static_cast_expression, // ***
	reinterpret_cast_expression, // ***
	const_cast_expression, // ***
	type_id_expression, // ***
	postfix_ctor_expression, // ***
	expression_list,
	pseudo_destructor_name,
	unary_expression,
	unary_inc_expression, // ***
	unary_dec_expression, // ***
	unary_logical_neg_expression, // ***
	unary_address_off_expression, // ***
	unary_dereference_expression, // ***
	unary_positive_expression, // ***
	unary_negative_expression, // ***
	unary_bit_comp_expression, // ***
	unary_size_of_expression, // ***
	unary_operator,
	new_expression,
	new_placement,
	new_type_id,
	new_declarator,
	direct_new_declarator_rhs_opt,
	direct_new_declarator,
	new_initializer,
	delete_expression,
	delete_array_expression, // ***
	cast_expression,
	pm_expression,
	multiplicative_expression,
	multiplicative_mul_expression, // ***
	multiplicative_div_expression, // ***
	multiplicative_mod_expression, // ***
	additive_expression,
	additive_add_expression, // ***
	additive_sub_expression, // ***
	shift_expression,
	shift_left_expression, // ***
	shift_right_expression, // ***
	relational_expression,
	relational_lt_expression, // ***
	relational_gt_expression, // ***
	relational_le_expression, // ***
	relational_ge_expression, // ***
	equality_expression,
	equality_eq_expression, // ***
	equality_ne_expression, // ***
	and_expression,
	exclusive_or_expression,
	inclusive_or_expression,
	logical_and_expression,
	logical_or_expression,
	conditional_expression,
	assignment_expression,
	assignment_mul_expression, // ***
	assignment_div_expression, // ***
	assignment_mod_expression, // ***
	assignment_add_expression, // ***
	assignment_sub_expression, // ***
	assignment_sr_expression, // ***
	assignment_sl_expression, // ***
	assignment_and_expression, // ***
	assignment_xor_expression, // ***
	assignment_or_expression, // ***
	assignment_operator,
	expression,
	constant_expression,
	statement,
	labeled_statement,
	labeled_statement_case, // ***
	labeled_statement_defualt, // ***
	expression_statement,
	compound_statement,
	statement_seq,
	selection_statement,
	selection_statement_if, // ***
	selection_statement_if_else, // ***
	selection_statement_switch, // ***
	condition,
	iteration_statement,
	iteration_statement_while, // ***
	iteration_statement_do_while, // ***
	iteration_statement_for, // ***
	for_init_statement,
	jump_statement,
	jump_statement_break, // ***
	jump_statement_continue, // ***
	jump_statement_return, // ***
	jump_statement_goto, // ***
	declaration_statement,
	declaration_seq,
	declaration,
	block_declaration,
	simple_declaration,
	decl_specifier,
	decl_specifier_seq,
	storage_class_specifier,
	function_specifier,
	type_specifier,
	simple_type_specifier,
	type_name,
	elaborated_type_specifier,
	elaborated_type_specifier_class_key, // ***
	elaborated_type_specifier_enum, // ***
	elaborated_type_specifier_typename, // ***
	enum_specifier,
	enumerator_list,
	enumerator_definition,
	enumerator,
	namespace_definition,
	named_namespace_definition,
	original_namespace_definition,
	extension_namespace_definition,
	unnamed_namespace_definition,
	namespace_body,
	namespace_alias_definition,
	qualified_namespace_specifier,
	using_declaration,
	using_directive,
	asm_definition,
	linkage_specification,
	init_declarator_list,
	init_declarator,
	declarator,
	ptr_declarator, // ***
	direct_declarator_rhs_opt,
	direct_declarator_rhs_func, // ***
	direct_declarator_rhs_arr, // ***
	direct_declarator,
	direct_declarator_func, // ***
	direct_declarator_arr, // ***
	ptr_operator,
	ref_operator, // ***
	cv_qualifier_seq,
	cv_qualifier,
	declarator_id,
	type_id,
	type_specifier_seq,
	abstract_declarator,
	direct_abstract_declarator_rhs_opt,
	direct_abstract_declarator_rhs_func, // ***
	direct_abstract_declarator_rhs_arr, // ***
	direct_abstract_declarator,
	direct_abstract_declarator_func, // ***
	direct_abstract_declarator_arr, // ***
	parameter_declaration_clause,
	parameter_declaration_list,
	parameter_declaration,
	parameter_declaration_init, // ***
	function_definition,
	function_definition_ctor, // ***
	function_body,
	initializer,
	initializer_clause,
	initializer_list,
	class_specifier,
	class_head,
	class_key,
	member_specification,
	member_declaration,
	member_declarator_list,
	member_declarator,
	pure_specifier,
	constant_initializer,
	base_clause,
	base_specifier_list,
	base_specifier,
	access_specifier,
	conversion_function_id,
	conversion_type_id,
	conversion_declarator,
	ctor_initializer,
	mem_initializer_list,
	mem_initializer,
	mem_initializer_id,
	operator_function_id,
	operator_,
	template_declaration,
	template_parameter_list,
	template_parameter,
	type_parameter,
	template_id,
	template_argument_list,
	template_argument,
	explicit_instantiation,
	explicit_specialization,
	try_block,
	function_try_block,
	handler_seq,
	handler,
	exception_declaration,
	throw_expression,
	exception_specification,
	type_id_list,
	declaration_seq_opt,
	TEMPLATE_opt,
	nested_name_specifier_opt,
	expression_list_opt,
	COLONCOLON_opt,
	new_placement_opt,
	new_initializer_opt,
	new_declarator_opt,
	expression_opt,
	statement_seq_opt,
	condition_opt,
	decl_specifier_seq_opt,
	init_declarator_list_opt,
	identifier_opt,
	enumerator_list_opt,
	TYPENAME_opt,
	initializer_opt,
	cv_qualifier_seq_opt,
	exception_specification_opt,
	constant_expression_opt,
	abstract_declarator_opt,
	type_specifier_seq_opt,
	direct_abstract_declarator_opt,
	parameter_declaration_list_opt,
	ELLIPSIS_opt,
	ctor_initializer_opt,
	COMMA_opt,
	member_specification_opt,
	base_clause_opt,
	member_declarator_list_opt,
	SEMICOLON_opt,
	pure_specifier_opt,
	constant_initializer_opt,
	access_specifier_opt,
	VIRTUAL_opt,
	conversion_declarator_opt,
	EXPORT_opt,
	handler_seq_opt,
	assignment_expression_opt,
	type_id_list_opt,

	ast_token, // ***
};

const char * ast_node_type_2_str(AstNodeType type);

class AstNode;

typedef boost::shared_ptr<AstNode> AstNodePtr;

typedef std::vector<AstNodePtr> AstNodePtrList;

typedef std::set<AstNodeType> AstNodeTypeSet;

class AstNode
{
	friend void output_ast_tree(std::ostream & ostr, AstNodePtr ast_root, int indent);

public:
	AstNode(AstNodeType type);

	virtual ~AstNode(void);

	AstNodeType getType(void) const;

	void pushChild(AstNodePtr child);

	void pushChildList(AstNodePtrList::const_iterator child_iter_begin, AstNodePtrList::const_iterator child_iter_end);

	//void pushLeftRecursionChild(AstNodePtr child, const AstNodeTypeSet & parent_type_set);

	//void pushLeftRecursionChildList(AstNodePtrList::const_iterator child_iter_begin, AstNodePtrList::const_iterator child_iter_end, const AstNodeTypeSet & parent_type_set);

	virtual std::ostream & output(std::ostream & ostr) const;

	template <class drived_class>
	drived_class & as(void)
	{
		drived_class * pret = dynamic_cast<drived_class *>(this);
		assert(NULL != pret);
		return *pret;
	}

	template <class drived_class>
	const drived_class & as(void) const
	{
		drived_class * pret = dynamic_cast<drived_class *>(this);
		assert(NULL != pret);
		return *pret;
	}

public:
	AstNodePtrList m_childs;

	AstNodeType m_type;
};

class AstUninitializedNode : public AstNode
{
public:
	AstUninitializedNode(AstNodeType type, const std::string & file, int line);

	virtual std::ostream & output(std::ostream & ostr) const;

public:
	std::string m_file;

	int m_line;
};

class AstTokenNode : public AstNode
{
public:
	AstTokenNode(int tokenID, const std::string & text, int line, int column, AstNodeType type = ast_token);

	virtual std::ostream & output(std::ostream & ostr) const;

public:
	int m_tokenID;

	std::string m_text;

	int m_line;

	int m_column;
};

class AstIdentifierNode : public AstNode
{
public:
	AstIdentifierNode(const std::string & text, AstNodeType type = identifier);

	virtual std::ostream & output(std::ostream & ostr) const;

public:
	std::string m_text;
};

std::ostream & output_indent(std::ostream & ostr, int indent);

void output_ast_tree(std::ostream & ostr, AstNodePtr ast_root, int indent = 0);

#endif // __AST_H__
